import cx from 'classnames';
import escape from 'lodash/escape';
import get from 'lodash/get';
import throttle from 'lodash/throttle';
import PropTypes from 'prop-types';
import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom';
import { ProgressBar } from 'react-bootstrap';
import VirtualList from 'react-tiny-virtual-list';
import api from 'app/api';
import Anchor from 'app/components/Anchor';
import Panel from 'app/components/Panel';
import i18n from 'app/lib/i18n';
import { formatBytes } from 'app/lib/numeral';
import styles from './dashboard.styl';

class Dashboard extends PureComponent {
    static propTypes = {
      show: PropTypes.bool,
      state: PropTypes.object
    };

    node = {
      virtualList: null
    };

    state = {
      virtualList: {
        visibleHeight: 0
      }
    };

    lines = [];

    renderItem = ({ index, style }) => (
      <div key={index} style={style}>
        <div className={styles.line}>
          <span className={cx(styles.label, styles.labelDefault)}>
            {index + 1}
          </span>
          {escape(this.lines[index])}
        </div>
      </div>
    );

    resizeVirtualList = throttle(() => {
      if (!this.node.virtualList) {
        return;
      }

      const el = ReactDOM.findDOMNode(this.node.virtualList);
      const clientHeight = Number(el.clientHeight) || 0;

      if (clientHeight > 0) {
        this.setState(state => ({
          virtualList: {
            ...state.virtualList,
            visibleHeight: el.clientHeight
          }
        }));
      }
    }, 32); // 60hz

    componentDidMount() {
      this.resizeVirtualList();
      window.addEventListener('resize', this.resizeVirtualList);
    }

    componentWillUnmount() {
      window.removeEventListener('resize', this.resizeVirtualList);
    }

    componentWillReceiveProps(nextProps) {
      if (nextProps.state.gcode.content !== this.props.state.gcode.content) {
        this.lines = get(nextProps, 'state.gcode.content', '')
          .split('\n')
          .filter(line => line.trim().length > 0);
      }
    }

    componentDidUpdate(prevProps) {
      if ((this.props.show !== prevProps.show) && this.props.show) {
        this.resizeVirtualList();
      }
    }

    render() {
      const { show, state } = this.props;
      const style = {
        display: show ? 'block' : 'none'
      };
      const filename = state.gcode.name || 'noname.nc';
      const filesize = state.gcode.ready ? formatBytes(state.gcode.size, 0) : '';
      const { sent = 0, total = 0 } = state.gcode;
      const { virtualList } = this.state;
      const rowHeight = 20;

      return (
        <Panel
          className={cx(styles.dashboard)}
          style={style}
        >
          <Panel.Heading style={{ height: 30 }}>
            {i18n._('G-code')}
          </Panel.Heading>
          <Panel.Body
            style={{ height: 'calc(100% - 30px)' }}
          >
            <div className="clearfix" style={{ marginBottom: 10 }}>
              <div className="pull-left text-nowrap">
                {state.gcode.ready && (
                  <Anchor
                    onClick={() => {
                      api.downloadGCode({ port: state.port });
                    }}
                  >
                    <strong>{filename}</strong>
                  </Anchor>
                )}
                {!state.gcode.ready && i18n._('G-code not loaded')}
              </div>
              <div className="pull-right text-nowrap">
                {filesize}
              </div>
            </div>
            <div style={{ marginBottom: 10 }}>
              <ProgressBar
                style={{ marginBottom: 0 }}
                bsStyle="info"
                min={0}
                max={total}
                now={sent}
                label={total > 0 && (
                  <span className={styles.progressbarLabel}>
                    {sent}&nbsp;/&nbsp;{total}
                  </span>
                )}
              />
            </div>
            <div
              ref={node => {
                this.node.virtualList = node;
              }}
              className={cx(
                styles.gcodeViewer,
                { [styles.gcodeViewerDisabled]: this.lines.length === 0 }
              )}
            >
              {this.lines.length > 0 && (
                <VirtualList
                  width="100%"
                  height={virtualList.visibleHeight}
                  style={{
                    padding: '0 5px'
                  }}
                  itemCount={this.lines.length}
                  itemSize={rowHeight}
                  renderItem={this.renderItem}
                  scrollToIndex={sent}
                />
              )}
              {this.lines.length === 0 && (
                <div className={styles.absoluteCenter}>
                  <img src="images/logo-square-256x256.png" alt="" />
                </div>
              )}
            </div>
          </Panel.Body>
        </Panel>
      );
    }
}

export default Dashboard;
